﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Web.Mvc;
using SportMeetingPlanner.Models;
using SportMeetingPlanner.ViewModels;

namespace SportMeetingPlanner.Controllers
{
    public class UserManagerController : Controller
    {
        private IUserRepository _repository;

        public UserManagerController() : this(new EntityUserManagerRepository()) { }
        public UserManagerController(IUserRepository repository)
        {
            _repository = repository;
        }

        //
        // GET: /UserManager/
        [Authorize()]
        public ActionResult Index()
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            return View(_repository.GetAllUsersOrdered());
        }

        //
        // GET: /UserManager/Details/5
        [Authorize()]
        public ActionResult Details(string userName)
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            user = _repository.GetUserByUserName(userName);
            return View(user);
        }

        //
        // GET: /UserManager/Create
        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /UserManager/Create
        [HttpPost]
        public ActionResult Create(RegisterModel userViewModel)
        {
            User user;
            if (ModelState.IsValid)
            {
                if (_repository.GetUserByUserName(userViewModel.UserName) == null)
                {
                    user = new User()
                    {
                        UserName = userViewModel.UserName,
                        TelephoneNumber = userViewModel.TelephoneNumber,
                        Email = userViewModel.Email,
                        FirstName = userViewModel.FirstName,
                        LastName = userViewModel.LastName,
                        Password = GetPasswordHash(userViewModel.Password),
                    };
                    _repository.CreateUser(user);
                    _repository.SaveChanges();
                    return RedirectToAction("Index");
                }
                else
                {
                    ModelState.AddModelError("UserManagerViewModel", "The user name is already taken.");
                }
            }

            return View(userViewModel);
        }

        //
        // GET: /UserManager/Edit/5
        [Authorize()]
        public ActionResult Edit(string userName)
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            user = _repository.GetUserByUserName(userName);
            ChangeUserInformationModel userViewModel = new ChangeUserInformationModel()
            {
                UserName = user.UserName,
                FirstName = user.FirstName,
                LastName = user.LastName,
                Email = user.Email,
                TelephoneNumber = user.TelephoneNumber,
                IsAdmin = user.IsAdmin
            };
            return View(userViewModel);
        }

        //
        // POST: /UserManager/Edit/5
        [HttpPost]
        [Authorize()]
        public ActionResult Edit(ChangeUserInformationModel userViewModel)
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            user = _repository.GetUserByUserName(userViewModel.UserName);
            if (ModelState.IsValid)
            {
                user.UserName = userViewModel.UserName;
                user.FirstName = userViewModel.FirstName;
                user.LastName = userViewModel.LastName;
                user.Email = userViewModel.Email;
                user.TelephoneNumber = userViewModel.TelephoneNumber;
                user.IsAdmin = userViewModel.IsAdmin;
                _repository.ModifyUser(user);
                _repository.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(userViewModel);
        }

        //
        // GET: /UserManager/Delete/5
        [Authorize()]
        public ActionResult Delete(string userName)
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            user = _repository.GetUserByUserName(userName);
            return View(user);
        }

        //
        // POST: /UserManager/Delete/5
        [HttpPost, ActionName("Delete")]
        [Authorize()]
        public ActionResult DeleteConfirmed(string userName)
        {
            User user = GetAuthenticatedUser();
            if (user == null || !user.IsAdmin)
            {
                return RedirectToAction("Index", "Home");
            }

            user = _repository.GetUserByUserName(userName);
            if (user.UserName == User.Identity.Name)
            {
                ModelState.AddModelError("SelfDeletion", "You are not allowed to delete yourself");
                return View(user);
            }
            else
            {
                _repository.DeleteUser(user.UserName);
                _repository.SaveChanges();
                return RedirectToAction("Index");
            }
        }

        private string GetPasswordHash(string passWord)
        {
            try
            {
                var passData = System.Text.Encoding.ASCII.GetBytes(passWord);
                string hashedPassword = Convert.ToBase64String(MD5.Create().ComputeHash(passData));
                return hashedPassword;
            }
            catch (ArgumentNullException)
            {
                return string.Empty;
            }
            catch (InvalidOperationException)
            {
                return string.Empty;
            }
            catch (EncoderFallbackException)
            {
                return string.Empty;
            }
        }

        protected override void Dispose(bool disposing)
        {
            _repository.Dispose();
            base.Dispose(disposing);
        }

        private User GetAuthenticatedUser()
        {
            User result = null;

            if (User.Identity.IsAuthenticated)
            {
                result = _repository.GetUserByUserName(User.Identity.Name);
            }

            return result;
        }
    }
}